using System;
using System.Collections.Generic;
using System.Text;
using GarageGames.Torque.T2D;
using GarageGames.Torque.Materials;
using Xyne.Components;
using Microsoft.Xna.Framework;
using GarageGames.Torque.Core;
using Microsoft.Xna.Framework.Graphics;
using GarageGames.Torque.Util;

namespace Xyne.Templates.PuzzlePieceTemplate
{
    /// <summary>
    /// 
    /// </summary>
    public class PlayerPieces : T2DStaticSprite
    {
        // The template instance
        private static PlayerPieces template = new PlayerPieces();
        public delegate void PlayerPiecesDoneCallback(PlayerPieces player);

        // The linkpoint IDs
        private String[] firstLinkPointNames = new String[]{ "F0", "F1", "F2", "F3" };
        private String[] secondLinkPointNames = new String[] { "S0", "S1", "S2", "S3" };

        private PlayerPiecesDoneCallback playerPiecesDoneCallback;
        private PuzzlePiece first;
        private PuzzlePiece second;

        #region Properties
        public static PlayerPieces Template
        {
            get { return template; }
        }

        public PlayerPiecesDoneCallback PlayerPiecesDone
        {
            get { return playerPiecesDoneCallback; }
            set { playerPiecesDoneCallback = value; }
        }

        public String[] FirstLinkPointNames
        {
            get { return firstLinkPointNames; }
        }

        public String[] SecondLinkPointNames
        {
            get { return secondLinkPointNames; }
        }

        public PuzzlePiece First
        {
            get { return first; }
            set
            {
                first = value;
                first.Position = new Vector2(this.Position.X - (first.Size.X / 2), this.Position.Y);
                first.Mount(this, firstLinkPointNames[0], true);
            }
        }

        public PuzzlePiece Second
        {
            get { return second; }
            set
            {
                second = value;
                second.Position = new Vector2(this.Position.X + (second.Size.X / 2)/* + 1*/, this.Position.Y);
                second.Mount(this, secondLinkPointNames[0], true);
            }
        }
        #endregion

        public PlayerPieces()
        {
            // Set the template and name
            IsTemplate = true;
            Name = Game.PlayerPiecesName;

            // Create the required blank (and invisible) material
            SimpleMaterial material = new SimpleMaterial();
            Material = material;
            Size = new Vector2(Game.PuzzlePieceWidth * 2, Game.PuzzlePieceHeight);
            Visible = false;
            // Set the object type
            ObjectType = TorqueObjectDatabase.Instance.GetObjectType(Name);

            // Add all the possible linkpoints for both halves of the player piece
            Components.AddComponent(new T2DLinkPointComponent());
            LinkPoints.AddLinkPoint(firstLinkPointNames[0], new Vector2(-0.5f, 0), 0);
            LinkPoints.AddLinkPoint(firstLinkPointNames[1], new Vector2(0, -0.5f), 0);
            LinkPoints.AddLinkPoint(firstLinkPointNames[2], new Vector2(0.5f, 0), 0);
            LinkPoints.AddLinkPoint(firstLinkPointNames[3], new Vector2(0, 0.5f), 0);
            LinkPoints.AddLinkPoint(secondLinkPointNames[0], new Vector2(0.5f, 0), 0);
            LinkPoints.AddLinkPoint(secondLinkPointNames[1], new Vector2(0, 0.5f), 0);
            LinkPoints.AddLinkPoint(secondLinkPointNames[2], new Vector2(-0.5f, 0), 0);
            LinkPoints.AddLinkPoint(secondLinkPointNames[3], new Vector2(0, -0.5f), 0);

            // Set collision parameters
            Collision.CollidesWith = TorqueObjectDatabase.Instance.GetObjectType(Game.PuzzlePieceName);
            Collision.ResolveCollision = new T2DResolveCollisionDelegate(OnCollision);
            T2DWorldLimitComponent limit = new T2DWorldLimitComponent();
            limit.WorldLimitResolveCollision = new T2DResolveCollisionDelegate(OnWorldCollision);
            Components.AddComponent(limit);
            Collision.CollisionMaterial = new T2DCollisionMaterial(0, 0, 0);

            // Remove current images
            ReadOnlyArray<T2DCollisionImage> images = Collision.Images;
            foreach (T2DCollisionImage collisionImage in images)
            {
                Collision.RemoveImage((T2DCollisionImage)collisionImage);
            }

            // Create a custom collision image
            T2DPolyImage image = new T2DPolyImage();
            Vector2[] points = new Vector2[4];
            points[0] = new Vector2(-0.9f, -1.0f);
            points[1] = new Vector2(-0.9f, 1.0f);
            points[2] = new Vector2(0.9f, 1.0f);
            points[3] = new Vector2(0.9f, -1.0f);
            image.CollisionPolyBasis = points;
            Collision.InstallImage(image);
        }

        public override void CopyTo(TorqueObject obj)
        {
            base.CopyTo(obj);
        }

        private void OnCollision(T2DSceneObject ourObject, T2DSceneObject theirObject, ref T2DCollisionInfo info,
                    T2DCollisionMaterial physicsMaterial, bool handleBoth)
        {
            // If the player pieces land on another piece
            if (info.Normal.Y < 0 && ((int)Math.Round(theirObject.Position.X) == (int)Math.Round(((PlayerPieces)ourObject).First.Position.X) ||
                                        (int)Math.Round(theirObject.Position.X) == (int)Math.Round(((PlayerPieces)ourObject).Second.Position.X)))
            {
                // Correct position and mock the speed
                ourObject.WarpToPosition(new Vector2(ourObject.Position.X, theirObject.Position.Y - (theirObject.Size.Y / 2) - (ourObject.Size.Y / 2)), 0);
                ourObject.Physics.VelocityY = theirObject.Physics.VelocityY;

                List<PuzzlePiece> pieces = new List<PuzzlePiece>();
                TorqueObjectDatabase.Instance.FindRegisteredObjects<PuzzlePiece>(ref pieces);
                foreach (PuzzlePiece piece in pieces)
                {
                    if (piece.MountedTo == ourObject)
                    {
                        Vector2 mountPosition = new Vector2();
                        float mountRotation;
                        piece.GetMountPosition(out mountPosition, out mountRotation);
                        piece.WarpToPosition(mountPosition, mountRotation);
                    }
                }

                // If the other piece is stationary (landed)
                if (theirObject.Physics.VelocityY == 0)
                {
                    if (ourObject is PlayerPieces)
                    {
                        PlayerPieces our = ourObject as PlayerPieces;

                        if (our.PlayerPiecesDone != null)
                        {
                            // Break apart
                            our.PlayerPiecesDone(our);
                        }
                    }
                }
            }
        }

        private void OnWorldCollision(T2DSceneObject ourObject, T2DSceneObject theirObject, ref T2DCollisionInfo info,
                    T2DCollisionMaterial physicsMaterial, bool handleBoth)
        {
            // If the player pieces land on the bottom of the world
            if (info.Normal.Y != 0 && ourObject is PlayerPieces)
            {
                PlayerPieces our = ourObject as PlayerPieces;
                our.WarpToPosition(new Vector2(our.Position.X, our.WorldLimit.MoveLimitMax.Y - (our.Size.Y / 2)), 0);

                List<PuzzlePiece> pieces = new List<PuzzlePiece>();
                TorqueObjectDatabase.Instance.FindRegisteredObjects<PuzzlePiece>(ref pieces);
                foreach (PuzzlePiece piece in pieces)
                {
                    if (piece.MountedTo == our)
                    {
                        Vector2 mountPosition = new Vector2();
                        float mountRotation;
                        piece.GetMountPosition(out mountPosition, out mountRotation);
                        piece.WarpToPosition(mountPosition, mountRotation);
                    }
                }

                if (our.PlayerPiecesDone != null)
                {
                    // Break apart
                    our.PlayerPiecesDone(our);
                }
            }
        }
    }
}
